package com.beantools.reflect.property;

import com.alibaba.fastjson.JSONObject;
import com.beantools.constants.BasicStandardTypes;
import com.beantools.entity.EntityStorage;
import com.beantools.execption.ClassException;
import com.beantools.execption.InformationException;
import com.beantools.execption.NotSupportObjectException;
import com.beantools.execption.PropertyException;
import com.beantools.filters.AbstractFilters;
import com.beantools.util.ArrayUtil;
import com.beantools.util.CollectionUtil;
import com.beantools.util.StringUtil;

import java.io.Serializable;
import java.util.*;

import static com.beantools.constants.SingleChar.*;
import static com.beantools.entity.enums.DateFormatEnum.ISO_DATETIME_FORMAT;
import static com.beantools.util.FastDateFormat.formatByEnum;
import static com.beantools.util.JavaTypeUtil.*;
import static com.beantools.util.ObjectUtil.isNotNull;
import static com.beantools.util.ObjectUtil.isNull;
import static com.beantools.util.StringUtil.getString;
import static com.beantools.util.StringUtil.isEmpty;
import static java.math.BigDecimal.*;

/**
 * 这是属性过滤器的类，比如有一个实体类，其有多个属性，但调用者只想
 * 拿到该类的某个或某些属性，因而，需要过滤出真正想要拿到的属性。
 * <p>
 * <pre>
 *     <code>
 *         public class Student {
 *              private Long id;
 *              private String no;
 *              public Student( Long id, String no) {
 *                  this.id = id;
 *                  this.no = no;
 *              }
 *              public Student() {}
 *              public Long getId() {return id;}
 *              public void setId(Long id) {this.id = id;}
 *              public String getNo() {return no;}
 *              public void setNo(String no) {this.no = no;}
 *          }
 *     </code>
 *     调用者现在通过这个方法，只要获取学号{@code no}，于是
 *     <code>
 *         String[] studentJson={"no"}；
 *     </code>
 * </pre>
 *
 * @author baoya
 * @version 1.0
 * @Documented
 * @see BuilderFilters
 * @since 1.1.0
 */
@SuppressWarnings("all")
public class PropertyFilters<R, T> extends AbstractFilters<R, T> implements Serializable {

    private static final long serialVersionUID = 4930544242759119363L;

    private List<EntityStorage> storages;

    /**
     * 需要过滤的数组，比如{"student.name:stuName","name",...}
     */
    private String[] strArray;

    /**
     * 在创建无参构造器时
     */
    public PropertyFilters() {
    }

    /**
     * 初始化{student.name:studentName,student.id:studentId,courseId}，这种
     * 数据格式的的字符串。也许，{@code Student}类中有很多属性，而且{@code
     * Student}类是{@code Course}类的属性，与此同时，{@code Course}类也有很
     * 多属性，但是，客户端程序员只要其中部分数据，因而，服务端调用此类来过滤
     * 数据。
     *
     * @param args 字符串格式的对象，如果不是字符串格式，则会抛出异常
     */
    @Override
    public void initFilter(Object args) throws NullPointerException, NotSupportObjectException {
        if (isNull(args)) {
            throw new NullPointerException("空指针异常，即参数不能为空");
        }
        if (args instanceof String) {
            throw new NotSupportObjectException("如果是字符串类型，可以使用类com.beantools.reflect.property的getProperty方法");
        }
        if (args instanceof Map) {
            strArray = makeMapStringArray((Map<R, T>) args);
        }
        if (args instanceof Collection) {
            strArray = makeCollStringArray((Collection) args);
        }
        if (args instanceof String[]) {
            strArray = (String[]) args;
        }
        if (ArrayUtil.containNullObject(strArray)) {
            throw new InformationException("源数据包含空对象");
        }
    }

    /**
     * 调用者将获取到的属性对象封装成JsonObject对象，如果你想了解更多有关fastjson框架的知识
     * 可以参考这个链接<a href="http://www.runoob.com/w3cnote/fastjson-intro.html">fastjson</a>
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObjStudents() {
     *               Student student1 = new Student();
     *               student1.setName("zby1");
     *               student1.setNo("23343434_1");
     *               Student student2 = new Student();
     *               student2.setName("zby1");
     *               student2.setNo("23343434_2");
     *               java.util.List list = new ArrayList();
     *               list.add(student1);
     *               list.add(student2);
     *               String[] strings = {"name:studentName", "no"};
     *               ArrayList arrayList = BuilderFilters.builderPropertyFilters().filterJsons(strings, list);
     *               System.out.println(arrayList);
     *           }
     *     </code>
     * </pre>
     * 如果你连接的是数据库，并且第三方db框架，比如mybatis、hibernate等等，其容器集合来源于数据库。
     *
     * @param propNames 参数数组，比如{student.name:studentName,student.id:studentId,courseId}
     * @param obj       当前类对象
     * @return 返回的是{@code JonObject}的实例化对象
     */
    public LinkedList<JSONObject> filerLinkedJsons(String[] propNames, Collection<Object> list) {
        List<JSONObject> jsonObjects = filterJsons(propNames, list, false);
        return isNull(jsonObjects) ? null : (LinkedList<JSONObject>) jsonObjects;
    }

    /**
     * 调用者将获取到的属性对象封装成JsonObject对象，如果你想了解更多有关fastjson框架的知识
     * 可以参考这个链接<a href="http://www.runoob.com/w3cnote/fastjson-intro.html">fastjson</a>
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObjStudents() {
     *               Student student1 = new Student();
     *               student1.setName("zby1");
     *               student1.setNo("23343434_1");
     *               Student student2 = new Student();
     *               student2.setName("zby1");
     *               student2.setNo("23343434_2");
     *               java.util.List list = new ArrayList();
     *               list.add(student1);
     *               list.add(student2);
     *               String[] strings = {"name:studentName", "no"};
     *               ArrayList arrayList = BuilderFilters.builderPropertyFilters().filterJsons(strings, list);
     *               System.out.println(arrayList);
     *           }
     *     </code>
     * </pre>
     * 如果你连接的是数据库，并且第三方db框架，比如mybatis、hibernate等等，其容器集合来源于数据库。
     *
     * @param propNames 参数数组，比如{student.name:studentName,student.id:studentId,courseId}
     * @param obj       当前类对象
     * @return 返回的是{@code JonObject}的实例化对象
     */
    public ArrayList<JSONObject> filterJsons(String[] propNames, Collection<Object> list) {
        List<JSONObject> jsonObjects = filterJsons(propNames, list, true);
        return isNull(jsonObjects) ? null : (ArrayList<JSONObject>) jsonObjects;
    }

    /**
     * 调用者将获取到的属性对象封装成JsonObject对象，如果你想了解更多有关fastjson框架的知识
     * 可以参考这个链接<a href="http://www.runoob.com/w3cnote/fastjson-intro.html">fastjson</a>
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObjStudents() {
     *               Student student1 = new Student();
     *               student1.setName("zby1");
     *               student1.setNo("23343434_1");
     *               Student student2 = new Student();
     *               student2.setName("zby1");
     *               student2.setNo("23343434_2");
     *               java.util.List list = new ArrayList();
     *               list.add(student1);
     *               list.add(student2);
     *               String[] strings = {"name:studentName", "no"};
     *               List list1 = BuilderFilters.builderPropertyFilters().filterJsons(strings, list, true);
     *               System.out.println(list1);
     *           }
     *     </code>
     * </pre>
     * 如果你连接的是数据库，并且第三方db框架，比如mybatis、hibernate等等，其容器集合来源于数据库。
     *
     * @param propNames   参数数组，比如{student.name:studentName,student.id:studentId,courseId}
     * @param obj         当前类对象
     * @param generJson   true表示生成{@code JsonObject}容器对象， false表示生成{@code Map}容器对象
     * @param isArrayList true表示生成的{@code HashMap}容器对象，或者生成{@code ArrayList}容器对象
     *                    false表示生成的{@code LinkedMap}容器对象，或者生成{@code LinkedList}容器对象，
     * @return 返回的是{@code JonObject}的实例化对象
     */
    public List<JSONObject> filterJsons(String[] propNames, Collection<Object> list, boolean isArrayList) {
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        List<JSONObject> jsonObjects = isArrayList ? new ArrayList(list.size()) : new LinkedList();
        for (Object obj : list) {
            jsonObjects.add(filerJson(propNames, obj));
        }
        return jsonObjects;
    }

    /**
     * 调用者将获取到的属性对象封装成JsonObject对象，如果你想了解更多有关fastjson框架的知识
     * 可以参考这个链接<a href="http://www.runoob.com/w3cnote/fastjson-intro.html">fastjson</a>
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObj() {
     *              Student student = new Student();
     *              student.setName("祝宝亚");
     *              Course course = new Course();
     *              course.setName("语文");
     *              course.setStudent(student);
     *              String[] strings = {"student.name:studentName", "name:courseName"};
     *              JSONObject jsonObject = BuilderFilters.builderPropertyFilters().filerJson(strings,course);
     *              System.out.println(jsonObject);
     *          }
     *     </code>
     * </pre>
     * <p>
     * 如果你的{@code object}是{@code Student}类的实例化对象，你想要获取其{@code name}的属性值，
     * 你可以这样写：
     * <pre>
     *     <code>
     *          public void testFilerObjStudent() {
     *               Student student = new Student();
     *               student.setName("祝宝亚");
     *               student.setStatus(ProjectStatusEnum.PROJECT_STATUS_REVIEWED);
     *               String[] strings = {"name:studentName"};
     *               JSONObject jsonObject = BuilderFilters.builderPropertyFilters().filerJson(strings,student);
     *               System.out.println(jsonObject);
     *          }
     *     </code>
     * </pre>
     *
     * @param propNames 参数数组，比如{student.name:studentName,student.id:studentId,courseId}
     * @param obj       当前类对象
     * @return 返回的是{@code JonObject}的实例化对象
     */
    public JSONObject filerJson(String[] propNames, Object obj) {
        Property property = Property.getInstance();
        JSONObject jsonObject = new JSONObject();
        initFilter(propNames);
        if (ArrayUtil.isEmpty(strArray) || ArrayUtil.containNullObject(strArray)) {
            throw new InformationException("过滤数组不能为空，且不能包含空对象");
        }
        for (int i = 0; i < strArray.length; i++) {
            String propName = filterSignColon(i, strArray[i]);
            List nameValueList = property.getNameValues(propName, obj);
            Object var = nameValueList.get(ROUND_DOWN);
            transform(jsonObject, nameValueList, var);
        }
        return jsonObject;
    }


    /**
     * 数据类型的转化，将<code>object</code>对象根据其类型转化为相应的对象，并装进当前对象的数据中。
     *
     * @param jsonObject    json实例化对象
     * @param nameValueList 对象属性和值的集合
     * @param var           当前对象
     */
    private void transform(JSONObject jsonObject, List nameValueList, Object var) {
        try {
            if (isNotNull(var)) {
                String simpleName = var.getClass().getSimpleName();
                Class clazz = var.getClass();
                if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_STRING)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoString(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_BIG_DECIMAL)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoBigDecimal(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_BOOLEAN)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoBoolean(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_BYTE)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoByte(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_DATE)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), formatByEnum(transformIntoDate(var, ISO_DATETIME_FORMAT), ISO_DATETIME_FORMAT));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_DOUBLE)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoDouble(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_FLOAT)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoFloat(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_INT)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoInt(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_INTEGER)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoInt(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_LONG)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoLong(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_SHORT)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoShort(var));
                } else if (simpleName.equalsIgnoreCase(BasicStandardTypes.JAVA_TYPE_TIMESTAMP)) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), formatByEnum(transformIntoDate(var, ISO_DATETIME_FORMAT), ISO_DATETIME_FORMAT));
                } else if (clazz.isEnum()) {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), transformIntoEnum(var));
                } else {
                    jsonObject.put(nameValueList.get(ROUND_UP).toString(), var);
                }
            } else {
                jsonObject.put(nameValueList.get(ROUND_UP).toString(), null);
            }
        } catch (ClassException e) {
            e.printStackTrace();
        } catch (PropertyException e) {
            e.printStackTrace();
        }
    }

    /**
     * 调用者将获取到的属性对象封装成这个可以是链表式的map，也可以是散列式的map。
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObj() {
     *              Student student = new Student();
     *              student.setName("祝宝亚");
     *              Course course = new Course();
     *              course.setName("语文");
     *              course.setStudent(student);
     *              String[] strings = {"student.name:studentName", "name:courseName"};
     *              LinkHashMap linkHashMap = BuilderFilters.builderPropertyFilters().filerLinkHashMap(strings,course);
     *              System.out.println(linkHashMap);
     *          }
     *     </code>
     * </pre>
     * <p>
     * 如果你的{@code object}是{@code Student}类的实例化对象，你想要获取其{@code name}的属性值，
     * 你可以这样写：
     * <pre>
     *     <code>
     *          public void testFilerObjStudent() {
     *               Student student = new Student();
     *               student.setName("祝宝亚");
     *               student.setStatus(ProjectStatusEnum.PROJECT_STATUS_REVIEWED);
     *               String[] strings = {"name:studentName"};
     *              LinkHashMap linkHashMap = BuilderFilters.builderPropertyFilters().filerLinkHashMap(strings,student);
     *              System.out.println(linkHashMap);
     *          }
     *     </code>
     * </pre>
     *
     * @param propertyNames 属性集合名称，比如{student.name:studentName,student.id:studentId,courseId}
     * @param object        当前类对象
     * @return 返回的是{@code LinkHashMap}的对象
     */
    public Map<String, Object> filerLinkHashMap(String[] propertyNames, Object object) {
        return filerMap(propertyNames, object, false);
    }

    /**
     * 调用者将获取到的属性对象封装成这个可以是链表式的map，也可以是散列式的map。
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObj() {
     *              Student student = new Student();
     *              student.setName("祝宝亚");
     *              Course course = new Course();
     *              course.setName("语文");
     *              course.setStudent(student);
     *              String[] strings = {"student.name:studentName", "name:courseName"};
     *              HashMap hashMap = BuilderFilters.builderPropertyFilters().filerHashMap(strings,course);
     *              System.out.println(hashMap);
     *          }
     *     </code>
     * </pre>
     * <p>
     * 如果你的{@code object}是{@code Student}类的实例化对象，你想要获取其{@code name}的属性值，
     * 你可以这样写：
     * <pre>
     *     <code>
     *          public void testFilerObjStudent() {
     *               Student student = new Student();
     *               student.setName("祝宝亚");
     *               student.setStatus(ProjectStatusEnum.PROJECT_STATUS_REVIEWED);
     *               String[] strings = {"name:studentName"};
     *              HashMap hashMap = BuilderFilters.builderPropertyFilters().filerHashMap(strings,student);
     *              System.out.println(hashMap);
     *          }
     *     </code>
     * </pre>
     *
     * @param propertyNames 属性集合名称，比如{student.name:studentName,student.id:studentId,courseId}
     * @param object        当前类对象
     * @return 返回的是{@code HashMap}对象
     */
    public Map<String, Object> filerHashMap(String[] propertyNames, Object object) {
        return filerMap(propertyNames, object, true);
    }

    /**
     * 调用者将获取到的属性对象封装成这个可以是链表式的map，也可以是散列式的map。
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <pre>
     *     <code>
     *           public void testFilerObj() {
     *              Student student = new Student();
     *              student.setName("祝宝亚");
     *              Course course = new Course();
     *              course.setName("语文");
     *              course.setStudent(student);
     *              String[] strings = {"student.name:studentName", "name:courseName"};
     *              Map map = BuilderFilters.builderPropertyFilters().filerMap(strings,course,true);
     *              System.out.println(map);
     *          }
     *     </code>
     * </pre>
     * <p>
     * 如果你的{@code object}是{@code Student}类的实例化对象，你想要获取其{@code name}的属性值，
     * 你可以这样写：
     * <pre>
     *     <code>
     *          public void testFilerObjStudent() {
     *               Student student = new Student();
     *               student.setName("祝宝亚");
     *               student.setStatus(ProjectStatusEnum.PROJECT_STATUS_REVIEWED);
     *               String[] strings = {"name:studentName"};
     *               Map map = BuilderFilters.builderPropertyFilters().filerMap(strings,student,true);
     *              System.out.println(map);
     *          }
     *     </code>
     * </pre>
     *
     * @param propertyNames 属性集合名称，比如{student.name:studentName,student.id:studentId,courseId}
     * @param object        当前类对象
     * @param isHashMap     如果为true，map指向的实现类为{@code HashMap}，
     *                      否则，为{@code LinkedHashMap}
     * @return 返回的{@code map}的实现类
     */
    public Map<String, Object> filerMap(String[] propertyNames, Object object, boolean isHashMap) {
        JSONObject jsonObject = filerJson(propertyNames, object);
        if (isNull(jsonObject) || jsonObject.size() <= 0) {
            return null;
        }
        Map map = isHashMap ? new HashMap(jsonObject.size()) : new LinkedHashMap(jsonObject.size());
        for (JSONObject.Entry entry : jsonObject.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }


    /**
     * 这是将容器对象转化为指定的字符串数组类型的数据的方法。
     * 如果包含 : .，但冒号之后是是空，类似于{@code student.name: }就抛出异常
     * 但是，如果不包含点号，但包含冒号，类似于{@code name: },程序可以除去冒号
     * <pre>
     *      <code>
     *            Set<String> set = new HashSet<>();
     *            set.add("student.name:studentName");
     *            set.add("no : ");
     *            String[] strings = BuilderFilters.builderPropertyFilters().makeCollStringArray(set);
     *            for (String string : strings) {
     *                 System.out.println(string);
     *            }
     *      </code>
     * </pre>
     *
     * @param coll 容器集合
     * @return 如果条件都成立的话，则返回数组字符串，否则，返回为空
     * @throws InformationException 提示异常信息
     */
    public String[] makeCollStringArray(Collection coll) throws InformationException {
        if (CollectionUtil.isEmpty(coll)) {
            return null;
        }
        String[] strings = new String[coll.size()];
        int index = 0;
        for (Iterator iterator = coll.iterator(); iterator.hasNext(); ) {
            Object obj = iterator.next();
            if (isNull(obj)) {
                throw new InformationException("第" + index + "个容器值不能为空");
            }
            strings[index++] = filterSignColon(index, makeObjToStr(index, obj));
        }
        return strings;
    }

    /**
     * 这是将Map对象转化为指定的字符串数组类型的数据的方法。比如下面的例子
     * <pre>
     *     <code>
     *          Map<String, String> map = new HashMap<String, String>();
     *          map.put("student.name","studentName");
     *          map.put("no",null);
     *          String[] strings = BuilderFilters.builderPropertyFilters().makeMapStringArray(map);
     *          for (String string : strings) {
     *              System.out.println(string);
     *         }
     *
     *         //查看其输出结果为：
     *              "no"
     * "student.name:studentName"
     *     </code>
     * </pre>
     *
     * @param map 只能存储字符串类型的容器
     * @return 返回字符串数组，如果字符串数据有值的情况下
     */
    public String[] makeMapStringArray(Map<R, T> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        String[] strings = new String[map.size()];
        int index = 0;
        for (Map.Entry<R, T> entry : map.entrySet()) {
            Object objKey = entry.getKey();
            Object value = entry.getValue();
            if (isNull(objKey)) {
                throw new InformationException("第" + index + "key值不能为空");
            }
            String strKey = makeObjToStr(index, objKey);
            if (strKey.contains(SIGN_COLON_OP) && isNull(value)) {
                throw new InformationException("第" + index + "key包含 “:”符号，但value值不能为空");
            }
            strings[index++] = EN_DOUBLE_QUOTATION +
                    strKey + (isNull(value) ? EN_DOUBLE_QUOTATION : (SIGN_COLON_OP + value + EN_DOUBLE_QUOTATION));
        }
        return strings;
    }

    /**
     * 这是私有方法，用来过滤这样的字符串。
     * 如果包含 : .，但冒号之后是是空，类似于{@code student.name: }就抛出异常
     * 如果不包含点号，但包含冒号，类似于{@code name: },程序可以除去冒号
     *
     * @param index 数组的下标
     * @param str   当前需要验证或过滤的字符串
     * @return 返回过滤后的字符串
     * @throws InformationException 字符串存在点和冒号，则冒号之后不能为空
     */
    private String filterSignColon(int index, String str) throws InformationException {
        if (str.contains(SIGN_COLON_OP) && str.contains(EN_POINT) && isEmpty(str.substring(0, str.lastIndexOf(SIGN_COLON_OP)))) {
            throw new InformationException("第" + index + "字符串存在点和冒号，则冒号之后不能为空");
        }
        if (str.contains(SIGN_COLON_OP) && !str.contains(EN_POINT) && isEmpty(str.substring(str.lastIndexOf(SIGN_COLON_OP) + ROUND_DOWN, str.length()))) {
            str = str.substring(0, str.lastIndexOf(SIGN_COLON_OP));
        }
        return str;
    }

    /**
     * 对容器{@code  collection}的值或{@code map}的key值进行简单的过滤
     * 如果通过了所有的验证，则返回字符串类型的值
     *
     * @param index  容器{@code  collection}或{@code map}下标
     * @param keyObj 容器{@code  collection}的值或{@code map}的key值
     * @return 返回的是字符串类型的值
     */
    private String makeObjToStr(int index, Object keyObj) {
        String str = getString(keyObj);
        if (isEmpty(str)) {
            throw new InformationException("第" + index + "个容器值不是字符串类型");
        }
        if (StringUtil.countContains(str, SIGN_COLON_OP) >= ROUND_CEILING) {
            throw new InformationException("第" + index + "key只能包含一个 “:”符号");
        }
        return str;
    }
}
